/* 
 * File:   Cliente.cpp
 * Author: Maximiliano Monzon (82341)
 * 
 * Created on October 20, 2012, 9:05 AM
 */
#include <cstdio>
#include <iostream>
#include <sstream>
#include "client_Cliente.h"
#include "client_Operacion.h"
#include "client_OperacionEco.h"
#include "client_OperacionCargaNuevoArchivo.h"
#include "common_ProtocoloConstantes.h"
#include "common_Excepcion.h"
#include "common_Descriptor.h"

using namespace std;
using namespace TP;
using namespace TP::Operaciones;
using namespace TP::Comunicacion;

Cliente::Cliente(ClientConfFileManager* pConfigurationManager, std::ostream& pLog): _log (pLog){
    
    _config = pConfigurationManager;
    _socket = new SocketAsincronico (pConfigurationManager->GetIpServidor(), pConfigurationManager->GetPuertoServidor());
    _observadorSocket = new ObservadorSocket(_socket);
    _repositorio = new Repositorio(pConfigurationManager->GetPathAU());
    _repositorioPoller = new RepositorioPoller(_repositorio, pConfigurationManager->GetIntervaloPolling());
    _fileService = new FileServiceProxy(_socket);
    _ecoService = new EcoServiceProxy(_socket);
}

Cliente::~Cliente() {
    
    delete _socket; 
    _socket = NULL;
    
    delete _observadorSocket;
    _observadorSocket = NULL;
    
    delete _repositorio;
    _repositorio = NULL;
    
    delete _repositorioPoller;
    _repositorioPoller = NULL;
    
    _config = NULL;
}

void Cliente::Iniciar() throw (Excepcion&){
    try
    {   
        _repositorioPoller->setRepositorioPollerManejadorEvento(reinterpret_cast<IRepositorioPollerManejadorEvento*> (this));
        _repositorioPoller->Iniciar();
    
        _socket->Iniciar();
        
        _observadorSocket->SetObservador((IObservadorSocketManejadorEvento*) this);
        //_observadorSocket->SetObservador(this);
        _observadorSocket->Iniciar();
        
    }
    catch (Excepcion& pEx)
    {
        pEx.expandirMensaje("No se puede inicar el cliente.");
        throw;
    }
}

void Cliente::Finalizar() throw (Excepcion&){
    try
    {
        _repositorioPoller->Finalizar();
        _observadorSocket->Finalizar();
        _socket->Finalizar();
    }
    catch (Excepcion& pEx)
    {
        pEx.expandirMensaje("No se puede finalizar el cliente.");
        throw;
    }
}

/* notificacionErrorConexion:
 *      Maneja los mensajes de error de conexion por parte del socket.
 */
void Cliente::notificarErrorConexion (IEnviante* pEnviante, const string& pMensaje){
    cout << endl << pMensaje << endl;
}

/* notificarMensajeEntrante:
 *      Maneja la notificacion de un mensaje entrante a traves del socket.
 */
void Cliente::notificarMensajeEntranteServidor (IEnviante* pEnviante, const string& pMensaje){
    
    try
    {
        vector<string> mensaje = hidratarMensaje(pMensaje);
        vector<IRespuestaServidorManejador*>::iterator it = _respuestaServidorManejadores.begin();
        
        while (it < _respuestaServidorManejadores.end())
        {
            if ((*it)->asociado(mensaje))
            {
                (*it)->procesarRespuesta(mensaje);
                break;
            }            
            ++it;
        }
    }
    catch (Excepcion &ex)
    {
        cerr << endl << ex.what() << endl;
    }
}

vector<string> Cliente::hidratarMensaje(const string& pMensaje) throw (Excepcion&) {
        
    // Hidrato el comando.
    try
    {
        std::stringstream ssParametros (pMensaje);
        string strParametro = "";
        vector<string> _mensaje;
        
        while (std::getline(ssParametros, strParametro, SEPARADOR_CAMPO))
        {
            std::stringstream ssHelper;
            ssHelper << strParametro;
            strParametro = "";
            ssHelper >> strParametro;

            if (strParametro.length () > 0)
            {
                _mensaje.push_back(strParametro);
            }
        }
        
        return _mensaje;
    }
    catch (int &)
    {
        throw;
    }
}

/* archivoNuevoEvento:
 *      Maneje la notificacion de nuevo evento por parte del RepositorioPoller
 */
void Cliente::archivoNuevoEvento(string & rutaArchivo){
    static int id = 0;
    
    Operacion* operacion = (Operacion*) new OperacionEco(id++, _ecoService);
    _respuestaServidorManejadores.push_back((IRespuestaServidorManejador*) operacion);
    operacion->ejecutar();
}


/* archivoModificadoEvento.
 *      Maneja la notificacion de archivo modificado por parte del poller.
 */
void Cliente::archivoModificadoEvento(string & rutaArchivo){

    cout << endl << rutaArchivo << endl;
}